home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AOL File Library: 2,801 to 2,900
/
aol-file-protocol-4400-2801-to-2900.zip
/
AOLDLs
/
C++ Files Library
/
Acere (PowerPlant, Game) 1.2
/
AcereÄ.sit
/
Acereƒ
/
Code
/
CardWell.cp
< prev
next >
Wrap
Text File
|
1995-03-04
|
18KB
|
663 lines
// ===========================================================================
// CardWell.cp ⌐1993 Metrowerks Inc. All rights reserved.
// ===========================================================================
//
// Class for an object that can draw itself and respond to mouse clicks
#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif
#include "CardWell.h"
#include "CardDeck.h"
#include "CardDragTask.h"
#include "WellDeck.h"
#include "CTextDoc.h"
#include "AcereApp.h"
#include <LView.h>
#include <LStream.h>
#include <PP_Messages.h>
#include <UDrawingState.h>
extern CTextDoc *theDoc;
extern unsigned long ourAvailRam;
// ---------------------------------------------------------------------------
// Ñ CreatePaneStream [static]
// ---------------------------------------------------------------------------
// Return a new Pane object initialized using data from a Stream
CardWell*
CardWell::CreateCardWell(
LStream *inStream)
{
return (new CardWell(inStream));
}
// ---------------------------------------------------------------------------
// Ñ CardWell()
// ---------------------------------------------------------------------------
// Default Constructor
CardWell::CardWell()
: LPane()/*,
/* LDragAndDrop(UQDGlobals::GetCurrentPort(), this) */
{
InitCard();
// LPane::CalcPortFrameRect(itsHelpRect);
}
// ---------------------------------------------------------------------------
// Ñ CardWell(const CardWell&)
// ---------------------------------------------------------------------------
// Copy Constructor
CardWell::CardWell(
const CardWell &inOriginal)
: LPane(inOriginal)
/* , LDragAndDrop(UQDGlobals::GetCurrentPort(), this) */
{
InitCard();
LPane::CalcPortFrameRect(itsHelpRect);
}
// ---------------------------------------------------------------------------
// Ñ CardWell(SPaneInfo&)
// ---------------------------------------------------------------------------
// Construct Pane from data in a struct
CardWell::CardWell(const SPaneInfo &inPaneInfo/*, const SViewInfo &inViewInfo*/)
: LPane(inPaneInfo/*, inViewInfo*/)
/* LDragAndDrop(UQDGlobals::GetCurrentPort(), this) */
{
// LView::LView(inPaneInfo, inViewInfo);
// InitPane(inPaneInfo);
InitCard();
}
// ---------------------------------------------------------------------------
// Ñ CardWell(LStream*)
// ---------------------------------------------------------------------------
// Construct Pane from data in a Stream
CardWell::CardWell(
LStream *inStream)
: LPane(inStream)
/* , LDragAndDrop(UQDGlobals::GetCurrentPort(), this) */
{
// SPaneInfo thePaneInfo;
// LView::LView(inStream);
// inStream->ReadData(&thePaneInfo, sizeof(SPaneInfo));
// InitPane(thePaneInfo);
InitCard();
}
void CardWell::InitCard(void)
{
Rect frame;
LPane::CalcPortFrameRect(itsHelpRect);
cardCanMove = isHighlighted = false;
itsCard = nil;
itsCardRgn = NewRgn();
OpenRgn();
CalcPortFrameRect(frame);
FrameRoundRect(&frame, 20, 20);
CloseRgn(itsCardRgn);
}
// ---------------------------------------------------------------------------
// Ñ ~CardWell
// ---------------------------------------------------------------------------
// Destructor
CardWell::~CardWell()
{
PutInside(nil);
if (sLastPaneClicked == this) {
sLastPaneClicked = nil;
}
DisposeRgn(itsCardRgn);
}
// ---------------------------------------------------------------------------
// Ñ Draw
// ---------------------------------------------------------------------------
// Try to draw contents of a Pane
//
// inSuperDrawRgnH specifies, in Port coordinates, the portion of the
// Pane's SuperView that needs to be drawn. Specify nil to bypass
// the intersection test.
//
// This is a wrapper function which calls DrawSelf if it is proper for
// the Pane to draw. This means that:
// > Pane's Visible property is on
// > Pane can be focused
// > Pane's Frame is in QuickDraw space
// > Pane's Frame intersects inSuperDrawRgnH
void CardWell::Draw(RgnHandle inSuperDrawRgnH)
{
Rect frame;
if ( IsVisible() &&
FocusDraw() &&
CalcPortFrameRect(frame) &&
((inSuperDrawRgnH == nil) || RectInRgn(&frame, inSuperDrawRgnH)) )
{
DrawSelf();
}
}
void CardWell::DrawSelf()
{
Rect frame;
CalcPortFrameRect(frame);
if (itsCard == nil)
{
EraseRgn(itsCardRgn);
FrameRgn(itsCardRgn);
}
else if (itsCard->card == kNoCard)
{
EraseRgn(itsCardRgn);
FrameRgn(itsCardRgn);
}
else
{
theDeck->DrawCard(itsCard, frame, isHighlighted);
}
}
Boolean CardWell::CanRemove(void) // can we remove cards from this pile?
{
return (true);
}
Boolean CardWell::PointInDropArea(Point inGlobalPt) // is it in our drop area?
{
return (true);
}
Boolean CardWell::CanDrop(PlayingCard *draggedCard)
{
if (itsCard == nil)
return (CanDropOnEmptySlot(draggedCard));
else if (itsCard->card == kNoCard)
return (CanDropOnEmptySlot(draggedCard));
else
return (CanDropOnSlot(draggedCard));
}
Boolean CardWell::ItemIsAcceptable(
DragReference inDragRef,
ItemReference inItemRef)
{
return (CanDrop((PlayingCard *)inItemRef));
}
/*void CardWell::EnterDropArea(DragReference inDragRef, Boolean inDragHasLeftSender)
//
// The cursor has just entered our area.
//
{ // protected, virtual
// Let LDragAndDrop do its thing (hilight the area)
LDragAndDrop::EnterDropArea(inDragRef, inDragHasLeftSender);
// And we'll do ours.
// PlaySound(gPlayEnterSound, rsrc_EnterSound);
}
void CardWell::LeaveDropArea (DragReference inDragRef)
//
// The cursor has just left the building. I repeat, the cursor has left the building.
//
{ // protected, virtual
// Let LDragAndDrop do its thing (removes the hilighting)
LDragAndDrop::LeaveDropArea (inDragRef);
// And we'll do ours.
// PlaySound(gPlayExitSound, rsrc_ExitSound);
}
void CardWell::InsideDropArea (DragReference inDragRef)
//
// The cursor is still in our area.
//
{ // protected, virtual
//
// Let LDragAndDrop do its thing - this is not really necessary, since
// the inherited version doesn't do anything. But it's safer this
// way because someday it might.
//
LDragAndDrop::InsideDropArea(inDragRef);
//
// And we'll do ours - we'll just read the mouse coordinates, but for this
// demo we won't do anything with them.
//
// The mouse location is where the mouse actually is on the screen. The
// alternative is the pinned location, which is _usually_ the same location,
// but can be different if the cursor is being constrained by a tracking handler.
// This is useful when you want an area within a view to be 'off-limits' to
// the ongoing drag.
//
// If we did want to do something based on where the cursor currently is in
// our area (such as indicating an insertion point or something), it would
// usually be best to use the pinned location for that work.
//
// Both mouse locations are returned in global screen coordinates
//
Point theMouseLocation;
Point thePinnedLocation;
::GetDragMouse(inDragRef, &theMouseLocation, &thePinnedLocation);
}
void CardWell::ReceiveDragItem(
DragReference inDragRef,
DragAttributes inDragAttrs,
ItemReference inItemRef,
Rect &inItemBounds) // In Local coordinates
//
// The user has dropped something in this view.
//
{
// PlaySound(gPlayDropSound, rsrc_DropSound);
::InvalRect(&inItemBounds);
//
// First, we'll figure out whether we want to copy the item(s), or only move the item(s).
//
// The rules for copying vs moving are spelled out in MD+DDK pp 19 through 21, and in
// a simplified form are: copy the item unless where it's coming from and
// where it's going to are the same window; then move it. If the option key
// was held down when the drag began, always copy it.
//
// Optional behaviour is for an application to also check the option
// key at the end of the drag. Copying then takes place if the option key was
// held down at the beginning _OR_ at the end.
//
Boolean optionKeyWasDown = CheckForOptionKey(inDragRef);
//
// Check to see if this View (the destination) is the
// same view (the source) that the object is coming from.
//
Boolean dragIsFromThisView = CheckIfViewIsAlsoSender(inDragRef);
//
// Information about the drag contents we'll be needing.
//
FlavorFlags theFlags; // We actually only use the flags to see if a flavor exists
Size theDataSize; // How much data there is for us.
CardStruct tCard; // Where we will put that data.
//
// Check to make sure the drag contains a cItemType item.
//
if (GetFlavorFlags(inDragRef, inItemRef, cCardWellType, &theFlags) == noErr) {
::GetFlavorDataSize(inDragRef, inItemRef, cCardWellType, &theDataSize);
if (theDataSize) {
ThrowIf_(theDataSize != sizeof(CardStruct)); // sanity check
//
// Get the data about the rectangle we are receiving.
//
::GetFlavorData(inDragRef, inItemRef, cCardWellType, &tCard, &theDataSize, 0L);
PlayingCard* theReceivedItem;
//
// Decide whether we want to move it or to make a new copy for ourselves
//
if (dragIsFromThisView && !optionKeyWasDown) {
//
// Move the item within this window
//
// Since we know it came from this window to this window,
// the pointer must still be good. This is the _only_ time we
// can rely on the pointer field in the structure.
//
// If you come up with (or already know of) a nicer way of
// managing this, please let me know. (gdignard@hookup.net)
//
//ÑÑ theReceivedItem = tCard.vPointerToSourceObject;
} else {
//
// Make a new copy of the dragged item
//
theReceivedItem = new PlayingCard(&tCard);
}
//
// Place it correctly in the view
//
// Check to see if the drag includes an HFS flavor. If it does, it means
// the flavor is coming from a clipping. This will be useful to know, since
// if the drag includes an HFS flavor, it means the user is dragging a file
// (ie in our case, a clipping). Since the user is dragging a file, the visual
// feedback they are getting is the outline of a file, not of the item. For that
// reason we'll want to drop the item centered around the current mouse position.
//
// If you want to actually see what this was designed to fix, change the !fromFinder
// in the following test to true, and drag from a clipping file to a CDDView.
//
Boolean fromFinder = (GetFlavorFlags(inDragRef, inItemRef,
flavorTypeHFS, &theFlags) == noErr);
if (!fromFinder) {
//
// Put it where the user dropped the item
//
theReceivedItem->PlaceInSuperFrameAt(inItemBounds.left, inItemBounds.top, true);
} else {
//
// It came from the Finder, place it centered around the drop point.
//
// theReceivedItem->PlaceInSuperFrameAt(
// inItemBounds.left - tCard.vItemSize.width / 2,
// inItemBounds.top - tCard.vItemSize.height / 2,
// true);
}
//
// If this view is on duty, make the received item the target
//
// if (IsOnDuty()) {
// SwitchTarget(theReceivedItem);
// }
}
}
}
Boolean CardWell::CheckForOptionKey(DragReference inDragRef)
{ // private
//
// We'll check whether the option key was down at either the beginning _or_ the
// end of the drag, since (a) it's the preferred behaviour and (b) its so easy to do.
//
Int16 theModifiersNow; // The state of the modifier keys right now
Int16 theModifiersAtMouseDown; // The state of the modifier keys when the drag began
Int16 theModifiersAtMouseUp; // The state of the modifier keys when the drag ended
::GetDragModifiers(inDragRef, &theModifiersNow, &theModifiersAtMouseDown, &theModifiersAtMouseUp);
return ((theModifiersAtMouseDown & optionKey) || (theModifiersAtMouseUp & optionKey));
}
Boolean CardWell::CheckIfViewIsAlsoSender(DragReference inDragRef)
{ // private
//
// Just a note: While we are using the drag attributes only at the end of the
// drag, they are also available to you during the drag.
//
// Drag Attributes are described in MD+DDK, page 2-31.
//
DragAttributes theDragAttributes;
::GetDragAttributes(inDragRef, &theDragAttributes);
return (theDragAttributes & dragInsideSenderWindow);
}
*/
Boolean CardWell::CanDropOnEmptySlot(PlayingCard *draggedCard)
{
// this will be overridden by most subclasses, which is why it's separate
// default behavior is that ANY card can be dropped on an empty slot
return (true);
}
Boolean CardWell::CanDropOnSlot(PlayingCard *draggedCard)
{
// this will be overridden by most subclasses.
// default behavior is that no card can be dropped on any card.
return (false);
}
void CardWell::AddCardToWell(CardWell *whichWell, PlayingCard *whichCard)
{
whichCard->itsOwner = this;
itsCard = whichCard;
}
void CardWell::RemoveCardFromWell(CardWell *whichWell, PlayingCard *whichCard)
{
itsCard = nil;
}
void CardWell::Click(SMouseDownEvent &inMouseDown)
{
CardWell *firstOwner, *secondOwner;
if ((itsCard == nil) && (theDoc->firstCard == nil)) // don't bother if there's no card!
return;
LPane::Click(inMouseDown);
if (sClickCount > 1) // user double-clicked
{
short j;
for (j=0; j < 4; j++)
{
secondOwner = theDoc->theDeckWells[j];
if (secondOwner->CanDrop(this->itsCard))
{
firstOwner = this;
secondOwner->AddCardToWell(this, this->itsCard);
this->RemoveCardFromWell(this, itsCard);
theDoc->firstCard = /*theDoc->secondCard = */ nil;
firstOwner->isHighlighted = false;
secondOwner->isHighlighted = false;
firstOwner->Draw(nil);
secondOwner->Draw(nil);
return;
}
}
}
if (theDoc->firstCard == nil)
{
if (CanRemove())
{
theDoc->firstCard = itsCard;
// theDoc->firstCard->itsCardInfo = itsCard->itsCardInfo;
isHighlighted = true;
// theDoc->firstCard->itsOwner->DrawSelf();
DrawSelf();
}
else
SysBeep(3);
}
else if (theDoc->firstCard == itsCard) // we're unclicking it
{
isHighlighted = false;
DrawSelf();
theDoc->firstCard = nil; // toggle selection
}
else
{
// theDoc->secondCard = itsCard;
// theDoc->secondCard->itsCardInfo = itsCard->itsCardInfo;
// this is a little tricky -- we need to call the subclass's method
if (itsCard == nil) // can't use the card method since card doesn't exist
{
if (this->CanDropOnEmptySlot(theDoc->firstCard))
{
firstOwner = theDoc->firstCard->itsOwner;
secondOwner = this;
theDoc->firstCard->itsOwner->RemoveCardFromWell(theDoc->firstCard->itsOwner,
theDoc->firstCard);
secondOwner->AddCardToWell(this, theDoc->firstCard);
theDoc->firstCard = /*theDoc->secondCard = */ nil;
firstOwner->isHighlighted = false;
secondOwner->isHighlighted = false;
firstOwner->DrawSelf();
secondOwner->DrawSelf();
}
}
else if (this->CanDrop(theDoc->firstCard))
{
// we can drag
// first we remove the card from its old slot
firstOwner = theDoc->firstCard->itsOwner;
secondOwner = this;
theDoc->firstCard->itsOwner->RemoveCardFromWell(theDoc->firstCard->itsOwner,
theDoc->firstCard);
// then we add it to the second slot
this->AddCardToWell(this, theDoc->firstCard);
theDoc->firstCard = /*theDoc->secondCard = */ nil;
firstOwner->isHighlighted = false;
secondOwner->isHighlighted = false;
firstOwner->DrawSelf();
secondOwner->DrawSelf();
}
else // we couldn't drop the card
{
// theDoc->secondCard = nil;
SysBeep(3);
}
}
}
/*void CardWell::ClickSelf(const SMouseDownEvent &inMouseDown)
{
SwitchTarget(this); // Make this item active
//
// Track item long enough to distinguish between a click to
// select, and the beginning of a drag
//
Boolean isDrag = ::WaitMouseMoved(inMouseDown.macEvent.where);
if (isDrag) {
//
// If we leave the window, the drag manager will be changing thePort,
// so we'll make sure thePort remains properly set.
//
mSuperView->FocusDraw();
CreateDragEvent(inMouseDown);
mSuperView->OutOfFocus(nil);
}
}
void CardWell::CreateDragEvent(const SMouseDownEvent &inMouseDown)
{ // private
if (itsCard->card == kNoCard)
return; // can't drag nuttin'
//
// We can create a Drag Task in one of two ways.
//
// The first is the quick and dirty way. The advantage is that you don't need
// to subclass LDragTask to drag the item. One disadvantage is that you don't
// get the opportunity to include a 'PICT' flavor in the drag. That means if
// the user double-clicks the item in the Finder he/she won't get a graphic
// depiction of the object. Another disadvantage is that we don't have the
// opportunity to define what the drag outline should look like. When we use
// LDragTask, the outline is always a rectangle.
//
// The second way is to subclass LDragTask, and have that subclass know about
// how to build a PICT of the current item to include in the drag, and also
// be able to define outlines customized to the item being dragged.
//
// You would normally choose one or the other way to go. I've done both so you
// can see how each is done. There's a menu item that allows you to switch back
// and forth between the two, so you can see the difference it makes to the user.
//
//
// This rect is going to be used by the Drag Task to draw the
// outline as the user drags the item around. LDragTask converts
// this rect into a region, which is then passed to the drag manager
// so it knows what the drag outline should look like.
//
Rect theRect;
CalcLocalFrameRect(theRect);
//
// Build a structure to contain the data we'll be passing to the drag event.
//
CardStruct theFlavorData;
FillDataStruct(&theFlavorData);
//
// Begin the drag task
//
LDragTask theDragTask( inMouseDown.macEvent, theRect, 1, cCardWellType,
&theFlavorData, sizeof(theFlavorData), 0L);
//
// If the drag is to the trash, it should be a move, not a copy
//
// CheckForTrash(&theDragTask);
}
void CardWell::FillDataStruct(CardStruct *theStruct)
{
theStruct->suit = itsCard->suit;
theStruct->card = itsCard->card;
theStruct->color = itsCard->color;
theStruct->itsOwner = itsCard->itsOwner;
// itsCardInfo = *theStruct;
}
*/
RgnHandle CardWell::GetCardRegion(void)
{
return itsCardRgn;
}
void CopyPString(ConstStr255Param srcString, Str255 destString)
{
BlockMove(srcString, destString, srcString[0] + 1L);
}